package zero.tech.core.event.service;

import java.util.concurrent.Callable;

import org.springframework.stereotype.Service;

import zero.tech.core.event.EventCallbackListener;
import zero.tech.core.event.EventListener;
import zero.tech.core.event.EventListenerManager;
import zero.tech.core.event.EventType;
import zero.tech.core.event.service.api.EventService;
import zero.tech.core.work.WorkManager;

@SuppressWarnings({ "unchecked", "rawtypes" })
@Service
public class EventServiceImpl implements EventService {
	public class Runner extends Thread {
		private EventListener listener;
		private Object[] objs;

		public Runner(EventListener listener, Object[] objs) {
			this.listener = listener;
			this.objs = objs;
		}

		@Override
		public void run() {
			listener.notifyEvent(objs);
		}
	}

	private void notifyEvent(final EventListener listener, Object... objs) {
		if (listener != null) {
			if (listener.asynchronous()) {
				new Runner(listener, objs).start();
			} else {
				listener.notifyEvent(objs);
			}
		}
	}

	public static class CallableRunner<T> implements Callable<T> {
		private EventCallbackListener<T> listener;
		private Object[] objs;

		public CallableRunner(EventCallbackListener<T> listener, Object[] objs) {
			this.listener = listener;
			this.objs = objs;
		}

		@Override
		public T call() throws Exception {
			return (T) listener.notifyEvent(objs);
		}

	}

	public <T> T notifyCallBackEvent(EventCallbackListener listener, Object... objs) {
		if (listener != null) {
			if (listener.asynchronous()) {
				CallableRunner call = new CallableRunner<T>(listener, objs);
				try {
					return (T) WorkManager.getManager().submitCallable(call);
				} catch (Exception e) {
					e.printStackTrace();
					return null;
				}
			} else {
				return (T) listener.notifyEvent(objs);
			}
		} else {
			return null;
		}
	}

	@Override
	public void engineNotify(EventType netEventType,Object... objs) {
		final EventListener listener = EventListenerManager.getManager()
				.getNetEventListener(netEventType);
		notifyEvent(listener, objs);
	}


	@Override
	public <T> T engineCallBack(EventType netEventType,Object... objs) {
		final EventCallbackListener<T> listener = EventListenerManager.getManager()
				.getNetCallbackEventListener(netEventType);
		return notifyCallBackEvent(listener, objs);
	}
}
